package com.seleniti.enpareja.web.desktop.client.control.factory;

import org.ioc.commons.flowcontrol.eventbus.IsEventBus;
import org.ioc.commons.flowcontrol.logincontroller.LoginController;
import org.ioc.commons.flowcontrol.messageboxfactory.MessageBoxFactory;
import org.ioc.commons.flowcontrol.notificator.Notificator;
import org.ioc.commons.flowcontrol.placecontroller.PlaceController;
import org.ioc.commons.flowcontrol.taskcontroller.TaskController;
import org.ioc.commons.i18n.DateTimeFormatter;
import org.ioc.commons.i18n.NumberFormatter;
import org.ioc.commons.impl.gwt.client.flowcontrol.eventbus.IsEventBusImpl;
import org.ioc.commons.impl.gwt.client.flowcontrol.notificator.GWTBrowserNotificator;
import org.ioc.commons.impl.gwt.client.flowcontrol.notificator.GWTBrowserNotificator.NotificationIconProvider;
import org.ioc.commons.impl.gwt.client.flowcontrol.placecontroller.GwtPlaceController;
import org.ioc.commons.impl.gwt.client.flowcontrol.taskcontroller.GwtTaskController;
import org.ioc.commons.impl.gwt.client.i18n.GwtDateTimeFormatter;
import org.ioc.commons.impl.gwt.client.i18n.GwtNumberFormatter;
import org.ioc.commons.impl.gwt.integration.client.dataaccess.localstorage.CookieStorage;
import org.ioc.commons.impl.gwt.integration.client.dataaccess.localstorage.Html5LocalStorage;
import org.ioc.commons.impl.gwt.integration.client.dataaccess.localstorage.LocalDataStringConverter;
import org.ioc.commons.integration.dataaccess.localstorage.LocalClientStorage;
import org.ioc.commons.model.clientfactory.ClientFactoryProvider;
import org.ioc.commons.model.globaldata.GlobalDataController;

import com.google.gwt.core.client.GWT;
import com.google.web.bindery.event.shared.SimpleEventBus;
import com.seleniti.enpareja.controller.common.GlobalData;
import com.seleniti.enpareja.controller.common.LocalData;
import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.controller.control.controller.LoginFailedCause;
import com.seleniti.enpareja.controller.control.controller.LoginParams;
import com.seleniti.enpareja.controller.control.factory.ClientFactory;
import com.seleniti.enpareja.controller.control.factory.EnParejaAppController;
import com.seleniti.enpareja.controller.control.factory.EnParejaExceptionController;
import com.seleniti.enpareja.controller.model.integration.service.EnParejaServiceManager;
import com.seleniti.enpareja.controller.ui.main.AppShell;
import com.seleniti.enpareja.web.appbase.client.control.controller.EnParejaExceptionControllerImpl;
import com.seleniti.enpareja.web.appbase.client.control.controller.EnParejaLoginController;
import com.seleniti.enpareja.web.appbase.client.control.controller.MessageBoxFactoryImpl;
import com.seleniti.enpareja.web.appbase.client.control.navigation.AppPlaceMapper;
import com.seleniti.enpareja.web.appbase.client.ui.main.AppShellWidget;
import com.seleniti.enpareja.web.desktop.client.control.controller.DesktopEnParejaAppControllerImpl;
import com.seleniti.enpareja.web.desktop.client.model.integration.service.impl.japtsy.EnParejaJAPTSYGAEServiceManagerImpl;
import com.seleniti.enpareja.web.desktop.client.ui.resources.CommonResources;

public class ClientFactoryImpl implements ClientFactory {
	private final SimpleEventBus gwtGlobalEventBus;
	private IsEventBusImpl globalEventBus;
	private GwtNumberFormatter numberFormatter;
	private GwtDateTimeFormatter dateTimeFormatter;
	private GlobalDataController<GlobalData> globalDataController;
	private ClientFactoryProvider<GwtTaskController> taskController;
	private LocalClientStorage<LocalData> localClientStorage;
	private ClientFactoryProvider<DesktopEnParejaAppControllerImpl> appProvider;
	private AppShellWidget shell;
	private final GwtPlaceController placeController;
	private final EnParejaDelegateAdapter onTryingGoBack = new EnParejaDelegateAdapter(this);
	private EnParejaJAPTSYGAEServiceManagerImpl serviceManager;
	private EnParejaLoginController loginController;
	private ClientFactoryProvider<MessageBoxFactory> messageBoxFactoryProvider;
	private ClientFactoryProvider<PlaceController> placeControllerProvider;
	private ClientFactoryProvider<? extends Notificator<NotificationIcons>> notificator;

	public ClientFactoryImpl() {
		this.gwtGlobalEventBus = new SimpleEventBus();
		this.globalEventBus = new IsEventBusImpl(gwtGlobalEventBus);
		AppPlaceMapper placeMapper = new AppPlaceMapper();
		this.placeController = new GwtPlaceController(placeMapper, placeMapper.getHistorymapper(), gwtGlobalEventBus,
				onTryingGoBack);

	}

	@Override
	public ClientFactoryProvider<? extends TaskController> getTaskController() {
		return (this.taskController == null) ? (this.taskController = ClientFactoryProvider.Tools
				.fixedValue(new GwtTaskController())) : this.taskController;
	}

	@Override
	public IsEventBus getGlobalEventBus() {
		return this.globalEventBus;
	}

	@Override
	public GlobalDataController<GlobalData> getGlobalDataController() {
		if (this.globalDataController == null) {
			this.globalDataController = new GlobalDataController<GlobalData>();
		}
		return this.globalDataController;
	}

	@Override
	public DateTimeFormatter getDateTimeFormatter() {
		if (this.dateTimeFormatter == null) {
			this.dateTimeFormatter = new GwtDateTimeFormatter();
		}
		return this.dateTimeFormatter;
	}

	@Override
	public NumberFormatter getNumberFormatter() {
		if (this.numberFormatter == null) {
			this.numberFormatter = new GwtNumberFormatter();
		}
		return this.numberFormatter;
	}

	@Override
	public LocalClientStorage<LocalData> getLocalClientStorage() {
		if (this.localClientStorage == null) {
			LocalDataStringConverter<LocalData> stringConverter = new LocalDataStringConverter<LocalData>() {

				@Override
				public Object fromString(LocalData key, String string) {
					switch (key) {
					case LAST_REMEMBER_ME_CHECK_STATUS:
						return Boolean.valueOf(string);
					case LAST_USER_NAME:
					default:
						return string;
					}
				}

				@Override
				public String toString(LocalData key, Object object) {
					return String.valueOf(object);
				}
			};
			this.localClientStorage = Html5LocalStorage.isSupported() ? new Html5LocalStorage<LocalData>("pozit_",
					stringConverter) : new CookieStorage<LocalData>("pozit_", stringConverter);
		}
		return this.localClientStorage;
	}

	@Override
	public ClientFactoryProvider<? extends EnParejaAppController> getAppController() {
		if (this.appProvider == null) {
			this.appProvider = ClientFactoryProvider.Tools.fixedValue(new DesktopEnParejaAppControllerImpl(this));
		}
		return this.appProvider;
	}

	@Override
	public AppShell getShell() {
		if (this.shell == null) {
			this.shell = new AppShellWidget();
		}
		return this.shell;
	}

	@Override
	public EnParejaExceptionController getExceptionController() {
		return EnParejaExceptionControllerImpl.get();
	}

	@Override
	public ClientFactoryProvider<MessageBoxFactory> getMessageBoxFactory() {
		if (this.messageBoxFactoryProvider == null) {
			this.messageBoxFactoryProvider = ClientFactoryProvider.Tools
					.<MessageBoxFactory> fixedValue(MessageBoxFactoryImpl.get());
		}
		return messageBoxFactoryProvider;
	}

	@Override
	public ClientFactoryProvider<PlaceController> getPlaceController() {
		if (this.placeControllerProvider == null) {
			this.placeControllerProvider = ClientFactoryProvider.Tools
					.<PlaceController> fixedValue(this.placeController);
		}
		return placeControllerProvider;
	}

	@Override
	public EnParejaServiceManager getServiceManager() {
		if (this.serviceManager == null) {
			this.serviceManager = GWT.create(EnParejaJAPTSYGAEServiceManagerImpl.class);
			this.serviceManager.setServiceEntryPoint(GWT.getModuleName() + "/dataServices/japtsy");
		}
		return this.serviceManager;
	}

	@Override
	public LoginController<LoggedUserInfo, LoginFailedCause, LoginParams, String> getLoginController() {

		return (this.loginController == null) ? (this.loginController = new EnParejaLoginController(getServiceManager()
				.serviceFactory().securityManagementService(), this.getGlobalDataController())) : this.loginController;
	}

	@Override
	public ClientFactoryProvider<? extends Notificator<NotificationIcons>> getNotificator() {
		if (this.notificator == null) {
			GWTBrowserNotificator<NotificationIcons> gwtNotification = GWTBrowserNotificator
					.<NotificationIcons> getNotificatorIfSupported(new NotificationIconProvider<NotificationIcons>() {

						@Override
						public String getIconUrl(NotificationIcons icon) {
							switch (icon) {
							case OK_ICON:
								return CommonResources.INSTANCE.tick32x32().getSafeUri().asString();
							case CANCEL_ICON:
								return CommonResources.INSTANCE.close_icon().getSafeUri().asString();
							case CALENDAR_ICON:
								return CommonResources.INSTANCE.calendarIcon().getSafeUri().asString();
							case APP_ICON:
							default:
								return "http://www.enpareja.net/images/tiny_logo.png";
							}
						}
					});
			this.notificator = ClientFactoryProvider.Tools.<Notificator<NotificationIcons>> fixedValue(gwtNotification);
		}
		return this.notificator;
	}

}
